import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import { SVGLoader } from "three/examples/jsm/loaders/SVGLoader";

export default class ThreeJs {
  stats: Stats | null = null;
  scene: THREE.Scene | null = null;
  camera: THREE.PerspectiveCamera | null = null;
  renderer: THREE.WebGLRenderer | null = null;
  ambientLight: THREE.AmbientLight | null = null;
  group: THREE.Group | null = null;
  controls: OrbitControls | null = null;
  axesHelper: THREE.AxesHelper | null = null;

  constructor() {
    this.init();
  }

  init(): void {
    this.setStats();
    this.setScene();
    this.setCamera();
    this.setRenderer();
    this.setCube();
    this.setControls();
    this.animate();
    this.onWindowResize();
    this.setAxesHelper();
  }

  onWindowResize(): void {
    window.addEventListener("resize", () => {
      if (this.camera && this.renderer) {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.render();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
      }
    });
  }
  //辅助工具
  setAxesHelper(): void {
    const helper = new THREE.AxesHelper(10);
    this.scene && this.scene.add(helper);
  }

  setStats(): void {
    this.stats = Stats();
    document.body.appendChild(this.stats.dom);
  }

  // 第一步新建一个场景
  setScene(): void {
    this.scene = new THREE.Scene();
  }

  // 新建透视相机
  setCamera(): void {
    // 第二参数就是 长度和宽度比 默认采用浏览器  返回以像素为单位的窗口的内部宽度和高度
    this.camera = new THREE.PerspectiveCamera(
      45,
      window.innerWidth / window.innerHeight,
      1,
      1000
    );
    this.camera.position.set(0, 0, 400);
  }

  // 设置渲染器
  setRenderer(): void {
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    // 设置画布的大小
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    //这里 其实就是canvas 画布  renderer.domElement
    document.body.appendChild(this.renderer.domElement);
  }

  // 设置环境光
  setLight(): void {
    if (this.scene) {
      // this.ambientLight = new THREE.AmbientLight(0xffffff); // 环境光
      // this.scene.add(this.ambientLight);

      this.scene.add(new THREE.AmbientLight(0x404040));

      const light = new THREE.DirectionalLight(0xffffff);
      light.position.set(1, 1, 1);
      this.scene.add(light);
    }
  }
  /**
   *  MeshBasicMaterial：为几何体赋予一种简单的颜色，或者显示几何体的线框
      MeshDepthMaterial：根据网格到相机的距离，该材质决定如何给网格染色
      MeshNormalMaterial：根据物体表面的法向量计算颜色
      MeshFaceMaterial：这是一种容器，可以在该容器中为物体的各个表面上设置不同的颜色
      MeshLambertMaterial：考虑光照的影响，可以创建颜色暗淡，不光亮的物体
      MeshPhongMaterial：考虑光照的影响，可以创建光亮的物体
      ShaderMaterial：使用自定义的着色器程序，直接控制顶点的放置方式，以及像素的着色方式
      LineBasicMaterial：可以用于THREE.Line几何体，从而创建着色的直线
      LineDashedMaterial：类似与基础材质，但可以创建虚线效果
   */

  // 创建网格模型
  setCube(): void {
    const loader = new SVGLoader();
    loader.load(
      "/assets/imgs/logo.svg",
      (data) => {
        const paths = data.paths;
        for (let i = 0; i < paths.length; i++) {
          const path = paths[i];
          this.group = new THREE.Group();

          const material = new THREE.MeshBasicMaterial({
            color: path.color,
            side: THREE.DoubleSide,
            depthWrite: false,
          });

          const shapes = SVGLoader.createShapes(path);

          for (let j = 0; j < shapes.length; j++) {
            const shape = shapes[j];
            const geometry = new THREE.ShapeGeometry(shape);

            geometry.center();
            const mesh = new THREE.Mesh(geometry, material);
            j == 1 && mesh.translateY(6);
            j == 2 && mesh.translateY(12);
            this.group && this.group.add(mesh);
          }
        }
        this.group && (this.group.position.y = 10);
        this.group && this.group.rotateX(-3.14);
        this.scene && this.group && this.scene.add(this.group);
      },
      // called when loading is in progresses
      function (xhr) {
        console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
      },
      // called when loading has errors
      function (error) {
        console.log("An error happened", error);
      }
    );
  }

  // 渲染
  render(): void {
    if (this.renderer && this.scene && this.camera) {
      this.renderer.render(this.scene, this.camera);
    }
  }

  // 动画
  animate(): void {
    if (this.controls && this.stats) {
      //更新控制器
      this.controls.update();
      this.render();

      //更新性能插件
      this.stats.update();
      requestAnimationFrame(this.animate.bind(this));
    }
    if (this.group) {
      const axis = new THREE.Vector3(0, 1, 0); //向量axis
      this.group.rotateOnAxis(axis, Math.PI / 100); //绕axis轴旋转π/8
    }
  }

  setControls(): void {
    if (this.camera && this.renderer) {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);

      // 如果使用animate方法时，将此函数删除
      //controls.addEventListener( 'change', render );
      // 使动画循环使用时阻尼或自转 意思是否有惯性
      this.controls.enableDamping = true;
      //动态阻尼系数 就是鼠标拖拽旋转灵敏度
      this.controls.dampingFactor = 0.25;
      //是否可以缩放
      this.controls.enableZoom = true;
      //是否自动旋转
      this.controls.autoRotate = false;
      //设置相机距离原点的最远距离
      this.controls.minDistance = 1;
      //设置相机距离原点的最远距离
      this.controls.maxDistance = 200;
      //是否开启右键拖拽
      this.controls.enablePan = true;
    }
  }
}
